package com.demo.common;

/**
 * 数字类型的处理工具类
 * 
 * @author ryuu.kk at 2013-07-05
 */
public final class NumberUtils {

	// private class
	private NumberUtils() {
	}

    /**
     * 最小位数
     *
     * @see     java.lang.Character#digit(char, int)
     * @see     java.lang.Character#forDigit(int, int)
     * @see     java.lang.Integer#toString(int, int)
     * @see     java.lang.Integer#valueOf(java.lang.String)
     */
    public static final int MIN_RADIX = 2;

    /**
     * 最大位数
     *
     * @see     java.lang.Character#digit(char, int)
     * @see     java.lang.Character#forDigit(int, int)
     * @see     java.lang.Integer#toString(int, int)
     * @see     java.lang.Integer#valueOf(java.lang.String)
     */
    public static final int MAX_RADIX = 62;
    
    private static final long   MULTMIN_RADIX_TEN =  Long.MIN_VALUE / 10;
    private static final long N_MULTMAX_RADIX_TEN = -Long.MAX_VALUE / 10;
    
    /**
     * 数字转换中,转换后所有可能出现的字母
     */
    final static char[] digits = {
	'0' , '1' , '2' , '3' , '4' , '5' ,
	'6' , '7' , '8' , '9' , 'a' , 'b' ,
	'c' , 'd' , 'e' , 'f' , 'g' , 'h' ,
	'i' , 'j' , 'k' , 'l' , 'm' , 'n' ,
	'o' , 'p' , 'q' , 'r' , 's' , 't' ,
	'u' , 'v' , 'w' , 'x' , 'y' , 'z' ,
	'A' , 'B' , 'C' , 'D' , 'E' , 'F' , 
	'G' , 'H' , 'I' , 'J' , 'K' , 'L' , 
	'M' , 'N' , 'O' , 'P' , 'Q' , 'R' , 
	'S' , 'T' , 'U' , 'V' , 'W' , 'X' , 
	'Y' , 'Z' 
    };
    
	/**
	 * long型数据的String型转化
	 * <br/>
	 * 一些long型数据(17位)压缩或解压成其他类型的数据(位数可指定)
	 * <br/>
	 * 压缩有编码:
	 * '0' , '1' , '2' , '3' , '4' , '5' ,
	 * '6' , '7' , '8' , '9' , 'a' , 'b' ,
	 * 'c' , 'd' , 'e' , 'f' , 'g' , 'h' ,
	 * 'i' , 'j' , 'k' , 'l' , 'm' , 'n' ,
	 * 'o' , 'p' , 'q' , 'r' , 's' , 't' ,
	 * 'u' , 'v' , 'w' , 'x' , 'y' , 'z' ,
     * 'A' , 'B' , 'C' , 'D' , 'E' , 'F' , 
     * 'G' , 'H' , 'I' , 'J' , 'K' , 'L' , 
     * 'M' , 'N' , 'O' , 'P' , 'Q' , 'R' , 
     * 'S' , 'T' , 'U' , 'V' , 'W' , 'X' , 
     * 'Y' , 'Z'  共62位
	 * @param i 原始long数据
	 * @param shift 数据位数, 如8位，16位,36位等 （最大62）
	 * 
	 * @return 压缩后字符串
	 */
	public static String toString(long i, int radix) {
		if (radix < MIN_RADIX || radix > MAX_RADIX)
		    radix = 10;
	        if (radix == 10)
	            return "";//toString(i);
	        char[] buf = new char[130];
	        int charPos = 128;
	        boolean negative = (i < 0);

	        if (!negative) {
	            i = -i;
	        }

	        while (i <= -radix) {
	            buf[charPos--] = digits[(int)(-(i % radix))];
	            i = i / radix;
	        }
	        buf[charPos] = digits[(int)(-i)];

	        if (negative) { 
	            buf[--charPos] = '-';
	        }

	        return new String(buf, charPos, (130 - charPos));
	}
	
    	/**
	 * 将压缩后的数据解压成long型数据
	 * @param s 压缩数据
	 * @param radix 位数
	 * @return 解压后long数据
	 * @throws NumberFormatException
	 */
	public static long parseLong(String s, int radix)
			throws NumberFormatException {
		if (s == null) {
			throw new NumberFormatException("null");
		}

		if (radix < MIN_RADIX) {
			throw new NumberFormatException("radix " + radix
					+ " less than Character.MIN_RADIX");
		}
		if (radix > MAX_RADIX) {
			throw new NumberFormatException("radix " + radix
					+ " greater than Character.MAX_RADIX");
		}

		long result = 0;
		boolean negative = false;
		int i = 0, max = s.length();
		long limit;
		long multmin;
		int digit;

		if (max > 0) {
			if (s.charAt(0) == '-') {
				negative = true;
				limit = Long.MIN_VALUE;
				i++;
			} else {
				limit = -Long.MAX_VALUE;
			}
			if (radix == 10) {
				multmin = negative ? MULTMIN_RADIX_TEN : N_MULTMAX_RADIX_TEN;
			} else {
				multmin = limit / radix;
			}
			if (i < max) {
				digit = Character.digit(s.charAt(i++), radix);
				if (digit < 0) {
					throw new NumberFormatException("For input string: \"" + s + "\"");
				} else {
					result = -digit;
				}
			}
			while (i < max) {
				// Accumulating negatively avoids surprises near MAX_VALUE
				digit = Character.digit(s.charAt(i++), radix);
				if (digit < 0) {
					throw new NumberFormatException("For input string: \"" + s + "\"");
				}
				if (result < multmin) {
					throw new NumberFormatException("For input string: \"" + s + "\"");
				}
				result *= radix;
				if (result < limit + digit) {
					throw new NumberFormatException("For input string: \"" + s + "\"");
				}
				result -= digit;
			}
		} else {
			throw new NumberFormatException("For input string: \"" + s + "\"");
		}
		if (negative) {
			if (i > 1) {
				return result;
			} else { /* Only got "-" */
				throw new NumberFormatException("For input string: \"" + s + "\"");
			}
		} else {
			return -result;
		}
	}
	
	public static final void main(String[] args) {
		long input = 12345678901234567L;
		System.out.println("-----------------------------");
		System.out.println("--  input : " + input + " (10radix)");
		System.out.println("--  radix : " + NumberUtils.toString(input, 62) + " (62radix)");
		System.out.println("--  unzip : " + NumberUtils.parseLong(NumberUtils.toString(input, 62), 10) + " (16radix)");	}
}
